package com.du.web.websocket.server;

import com.alibaba.fastjson.JSON;
import com.du.web.websocket.SysConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @desc:
 * @author: shuangdu
 * @date: 2021/5/28
 * @since: 1.8
 */
@Service
@Slf4j
@ServerEndpoint(value = "/socket/{uid}")
public class WebSocketServer {

    private static SysConfig sysConfig;

    /**
     * webSocket注入bean
     * 1
     */
    @Autowired
    public void setSysConfig(SysConfig sysConfig) {
        WebSocketServer.sysConfig = sysConfig;
    }

    private static AtomicInteger onlineCount =  new AtomicInteger();

    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "uid") String uid) {
        log.info("{}", sysConfig.getAuthPriKey());
        sessionPools.put(uid, session);
        addOnlineCount();
        log.info(uid + "加入webSocket！当前人数为" + onlineCount);
        try {
            sendMessage(session, "欢迎" + uid + "加入连接！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void OnClose(@PathParam(value = "uid") String uid) {
        sessionPools.remove(uid);
        subOnlineCount();
        log.info(uid + "断开webSocket连接！当前人数为" + onlineCount);
    }

    @OnMessage
    public void OnMessage(ByteBuffer bf) throws Exception{
        String msg = getString(bf);
        log.info("接受数据: {}", msg);
        MsgInfo msgInfo = JSON.parseObject(msg, MsgInfo.class);

        if (msgInfo.getToUserId() != null && !"".equals(msgInfo.getToUserId())) {
            sendInfoTo(msgInfo.getToUserId(), msgInfo.getContentText());
        } else {
            sendInfo(msg);
        }

    }

    public String getString(ByteBuffer buffer) {
        Charset charset = null;
        CharsetDecoder decoder = null;
        CharBuffer charBuffer = null;
        try {
            charset = Charset.forName("UTF-8");
            decoder = charset.newDecoder();
            //用这个的话，只能输出来一次结果，第二次显示为空
            // charBuffer = decoder.decode(buffer);
            charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
            return charBuffer.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return "error";
        }
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("发生错误");
        throwable.printStackTrace();
    }

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
//                log.info("发送数据：" + message);
                session.getBasicRemote().sendBinary(ByteBuffer.wrap(message.getBytes()));
            }
        }
    }
    //给指定用户发送信息
    public void sendInfo(String message){
        for (Session session: sessionPools.values()) {
            try {
                sendMessage(session, message);
            } catch(Exception e){
                log.error("发送异常!", e);
            }
        }
    }

    //给指定用户发送信息
    public void sendInfoTo(String userId, String message){
        Session session = sessionPools.get(userId);
        try {
            sendMessage(session, message);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void addOnlineCount(){
        onlineCount.incrementAndGet();
    }

    public static void subOnlineCount() {
        onlineCount.decrementAndGet();
    }


    static class MsgInfo implements Serializable {
        private String sendId;
        private String toUserId;
        private String contentText;

        public String getSendId() {
            return sendId;
        }

        public void setSendId(String sendId) {
            this.sendId = sendId;
        }

        public String getToUserId() {
            return toUserId;
        }

        public void setToUserId(String toUserId) {
            this.toUserId = toUserId;
        }

        public String getContentText() {
            return contentText;
        }

        public void setContentText(String contentText) {
            this.contentText = contentText;
        }
    }
}
